home *** CD-ROM | disk | FTP | other *** search
- unit Mime;
-
- interface
-
- uses Classes,SysUtils,Forms,Dialogs;
-
- const
- MaxChars = 57;
-
- type
- TBinBytes = array[1..MaxChars] of byte;
- TTxtBytes = array[1..2*MaxChars] of byte;
- T24Bits = array[0..8*MaxChars] of boolean;
-
- EUUInvalidCharacter = class(Exception)
- constructor Create;
- end;
-
- EMIMEError = class(Exception);
-
- {$IFDEF UseHuge}
- TTextStream = class(TMemoryStream)
- public
- procedure Write(const s : string);
- procedure Read(var s : string);
- end;
- {$ENDIF}
-
- TBase64 = class
- private
- {$IFDEF UseHuge}
- TextStream : TTextStream;
- {$ELSE}
- TextStream : TStringList;
- {$ENDIF}
- Stream : TStream;
- CurSection : byte;
- A24Bits : T24Bits;
- FOnProgress : TNotifyEvent;
- FOnStart : TNotifyEvent;
- FOnEnd : TNotifyEvent;
- function GenerateTxtBytes(tb : TBinBytes; NumOfBytes : byte) : string;
- procedure GenerateBinBytes(InS : string; BufPtr : pointer;
- var BytesGenerated : word);
- function ByteFromTable(Ch : Char) : byte;
- procedure DoProgress(Sender : TObject);
- procedure DoStart(Sender : TObject);
- procedure DoEnd(Sender : TObject);
- public
- Progress : Integer;
- ProgressStep : Integer;
- Canceled : boolean;
- Table : string;
- {$IFDEF UseHuge}
- constructor Create(AStream : TStream; ATextStream : TTextStream);
- {$ELSE}
- constructor Create(AStream : TStream; ATextStream : TStringList);
- {$ENDIF}
- procedure Encode;
- procedure Decode;
- property OnProgress : TNotifyEvent read FOnProgress
- write FOnProgress;
- property OnStart : TNotifyEvent read FOnStart write FOnStart;
- property OnEnd : TNotifyEvent read FOnEnd write FOnEnd;
- end;
-
- TQuotedPrintable = class(TComponent)
- private
- { Private declarations }
- protected
- { Protected declarations }
- Stream : TStream;
- Lines : TStringList;
- procedure ReplaceHiChars(var s : string);
- procedure ReplaceHex(var s : string);
- procedure ReformatParagraph(Buf : PChar; Len : Integer;
- TL : TStringList);
- public
- { Public declarations }
- Canceled : boolean;
- constructor Create(AStream : TStream; ALines : TStringList);
- procedure Encode;
- procedure Decode;
- published
- { Published declarations }
- end;
-
- function GetContentType(const FileName : string) : string;
- function MakeUniqueID : string;
-
- implementation
-
- constructor EUUInvalidCharacter.Create;
- begin
- inherited Create('Invalid character in the input file');
- end;
-
- {$IFDEF UseHuge}
- {TTextStream}
- procedure TTextStream.Write(const s : string);
- var
- Buf : array[0..255] of Char;
- sLen : byte absolute s;
- begin
- StrPCopy(@Buf,Concat(s,^M^J));
- inherited Write(Buf,StrLen(@Buf));
- end;
-
- procedure TTextStream.Read(var s : string);
- var
- sLen : byte absolute s;
- Ch : Char;
- begin
- Ch:=#00; s:='';
- repeat
- inherited Read(Ch,1);
- if not (Ch in [^M,^J]) then
- s:=Concat(s,Ch);
- until Ch=^J;
- end;
- {$ENDIF}
-
- {implementation for TBase64}
- {$IFDEF UseHuge}
- constructor TBase64.Create(AStream : TStream; ATextStream : TTextStream);
- {$ELSE}
- constructor TBase64.Create(AStream : TStream; ATextStream : TStringList);
- {$ENDIF}
- begin
- inherited Create;
- Stream:=AStream;
- TextStream:=ATextStream;
- ProgressStep:=10;
- Table:='ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
- FillChar(A24Bits,SizeOf(A24Bits),0);
- end;
-
- procedure TBase64.DoProgress(Sender : TObject);
- begin
- if Assigned(FOnProgress) then
- FOnProgress(Sender);
- end;
-
- procedure TBase64.DoStart(Sender : TObject);
- begin
- if Assigned(FOnStart) then
- FOnStart(Sender);
- end;
-
- procedure TBase64.DoEnd(Sender : TObject);
- begin
- if Assigned(FOnEnd) then
- FOnEnd(Sender);
- end;
-
- function TBase64.GenerateTxtBytes(tb : TBinBytes; NumOfBytes : byte) : string;
- var
- i,j,k,b,m : word;
- s : string;
- begin
- k:=0;
- FillChar(A24Bits,SizeOf(T24Bits),0);
- for i:=1 to MaxChars do
- begin
- b:=tb[i];
- for j:=7 DownTo 0 do
- begin
- m:=1 shl j;
- if (b and m = m) then
- A24Bits[k]:=true;
- Inc(k);
- end;
- end;
- s:=''; k:=0; m:=4*(MaxChars div 3);
- for i:=1 to m do
- begin
- b:=0;
- for j:=5 DownTo 0 do
- begin
- if A24Bits[k] then b:= b or (1 shl j);
- Inc(k);
- end;
- s[i]:=Table[b+1];
- end;
- if (NumOfBytes=MaxChars) or (NumOfBytes mod 3=0) then
- s[0]:=Char(4*NumOfBytes div 3)
- else
- begin
- s[0]:=Char(4*NumOfBytes div 3+1);
- while (Length(s) mod 4)<>0 do
- s:=Concat(s,'=');
- end;
- Result:=s;
- end;
-
- procedure TBase64.Encode;
- var
- BytesRead : word;
- ABinBytes : TBinBytes;
- Total : LongInt;
- begin
- DoStart(Self);
- TextStream.Clear;
- Progress:=0; Total:=0; Canceled:=false;
- try
- repeat
- FillChar(ABinBytes,SizeOf(TBinBytes),0);
- BytesRead:=Stream.Read(ABinBytes,MaxChars);
- Inc(Total,BytesRead);
- {$IFDEF UseHuge}
- TextStream.Write(GenerateTxtBytes(ABinBytes,BytesRead));
- {$ELSE}
- TextStream.Add(GenerateTxtBytes(ABinBytes,BytesRead));
- {$ENDIF}
- Progress:=Round(100*Total/Stream.Size);
- if Progress mod ProgressStep = 0 then
- DoProgress(Self);
- Application.ProcessMessages;
- until (BytesRead<MaxChars) or Canceled;
- finally
- Progress:=100;
- DoProgress(Self);
- if Canceled then TextStream.Clear;
- DoEnd(Self);
- end;
- end;
-
- function TBase64.ByteFromTable(Ch : Char) : byte;
- var
- i : byte;
- begin
- i:=1;
- while (Ch<>Table[i]) and (i<=64) do Inc(i);
- if i>64 then
- begin
- if Ch='=' then Result:=0
- else raise EUUInvalidCharacter.Create;
- end;
- Result:=i-1;
- end;
-
- procedure TBase64.GenerateBinBytes(InS : string; BufPtr : pointer;
- var BytesGenerated : word);
- var
- i,j,k,b,m : word;
- InSLen : byte absolute InS;
- ActualLen : byte;
- begin
- FillChar(BufPtr^,MaxChars,0);
- FillChar(A24Bits,SizeOf(T24Bits),0);
- k:=0;
- for i:=1 to InSLen do
- begin
- b:=ByteFromTable(InS[i]);
- for j:=5 DownTo 0 do
- begin
- m:=1 shl j;
- if (b and m = m) then
- A24Bits[k]:=true;
- Inc(k);
- end;
- end;
- k:=0;
- if InSLen<>4*MaxChars div 3 then
- begin
- ActualLen:=3*InSLen div 4;
- while InS[InSLen]='=' do
- begin
- Dec(ActualLen);
- Dec(InSLen);
- end;
- end
- else
- ActualLen:=MaxChars;
- for i:=1 to ActualLen do
- begin
- b:=0;
- for j:=7 DownTo 0 do
- begin
- if A24Bits[k] then b:= b or (1 shl j);
- Inc(k);
- end;
- byte(PChar((PChar(BufPtr)+i-1))^):=b;
- end;
- BytesGenerated:=i;
- end;
-
- procedure TBase64.Decode;
- var
- ATxtBytes : TTxtBytes;
- BytesGenerated : word;
- Total : LongInt;
- s : string;
- p : pointer;
- {$IFNDEF UseHuge}
- i : LongInt;
- {$ENDIF}
- begin
- DoStart(Self);
- Progress:=0;
- Canceled:=false;
- {$IFNDEF UseHuge}
- i:=0;
- {$ENDIF}
- try
- GetMem(p,MaxChars);
- Total:=0;
- repeat
- FillChar(p^,MaxChars,0);
- {$IFDEF UseHuge}
- TextStream.Read(s);
- {$ELSE}
- s:=TextStream[i];
- {$ENDIF}
- GenerateBinBytes(s,p,BytesGenerated);
- Stream.Write(p^,BytesGenerated);
- Inc(Total,BytesGenerated);
- {$IFDEF UseHuge}
- Progress:=Round(100*Total/TextStream.Size);
- {$ELSE}
- Progress:=Round(100*i/(TextStream.Count-1));
- {$ENDIF}
- if Progress mod ProgressStep = 0 then
- DoProgress(Self);
- Application.ProcessMessages;
- {$IFDEF UseHuge}
- until (TextStream.Position>=TextStream.Size) or Canceled;
- {$ELSE}
- Inc(i);
- until (i>=TextStream.Count);
- {$ENDIF}
- finally
- Progress:=100;
- DoProgress(Self);
- FreeMem(p,MaxChars);
- DoEnd(Self);
- end;
- end;
-
- {implementation for TQuotedPrintable}
-
- const
- BufSize=$6000;
-
- constructor TQuotedPrintable.Create(AStream : TStream; ALines : TStringList);
- begin
- Stream:=AStream;
- Lines:=ALines;
- Canceled:=false;
- end;
-
- procedure TQuotedPrintable.ReplaceHiChars(var s : string);
- var
- sLen : byte absolute s;
- i : byte;
- begin
- i:=1;
- while i<sLen do
- begin
- if Ord(s[i]) in [0..31,61,128..255] then
- begin
- Insert(Concat('=',IntToHex(Ord(s[i]),2)),s,i+1);
- Delete(s,i,1);
- Inc(i,2);
- end;
- Inc(i);
- end;
- end;
-
- procedure TQuotedPrintable.ReformatParagraph(Buf : PChar; Len : Integer;
- TL : TStringList);
- var
- i : Integer;
- cp,sp : PChar;
- s : string;
- sLen : byte absolute s;
- Finished : boolean;
- begin
- sp:=Buf;
- TL.Clear;
- repeat
- cp:=sp+Len;
- Finished:=cp>StrEnd(Buf);
- if Finished then cp:=StrEnd(Buf)
- else
- begin
- while (cp^<>' ') and (cp>sp) do Dec(cp);
- if cp=sp then
- cp:=sp+Len;
- end;
- sLen:=cp-sp;
- move(sp^,s[1],sLen);
- if not Finished then s:=Concat(s,'=');
- ReplaceHiChars(s);
- TL.Add(s);
- sp:=cp;
- until Finished;
- end;
-
- procedure TQuotedPrintable.Encode;
- var
- j : Integer;
- Ch : Char;
- s : string;
- Buf : PChar;
- Finished : boolean;
- TempLines : TStringList;
- begin
- Buf:=StrAlloc(BufSize);
- TempLines:=TStringList.Create;
- try
- repeat
- {Read a paragraph}
- j:=0;
- FillChar(Buf^,BufSize,0);
- repeat
- if j>=BufSize then
- raise EMIMEError.Create('Paragraph is too large');
- Stream.Read(Ch,1);
- if Stream.Position=Stream.Size then
- begin
- Finished:=true;
- move(Ch,(Buf+j)^,1);
- Inc(j);
- end
- else
- if Ch in [^M,^J] then
- begin
- Finished:=true;
- Stream.Read(Ch,1);
- if not (Ch in [^M,^J])
- then Stream.Position:=Stream.Position-1;
- end
- else
- begin
- Finished:=false;
- move(Ch,(Buf+j)^,1);
- Inc(j);
- end;
- Application.ProcessMessages;
- until Finished;
- ReformatParagraph(Buf,65,TempLines);
- if TempLines.Count=0 then Lines.Add('')
- else Lines.AddStrings(TempLines);
- until (Stream.Position=Stream.Size) or Canceled;
- finally
- TempLines.Free;
- StrDispose(Buf);
- end;
- end;
-
- procedure TQuotedPrintable.ReplaceHex(var s : string);
- var
- i : byte;
- sLen : byte absolute s;
- Hex : byte;
- begin
- i:=1;
- while i<sLen do
- begin
- if (s[i]='=') then
- begin
- try
- Hex:=StrToInt('$'+Copy(s,i+1,2));
- Delete(s,i,3);
- Insert(Char(Hex),s,i);
- except
- on EConvertError do {Do nothing}
- else raise;
- end;
- end;
- Inc(i);
- end;
- end;
-
- procedure TQuotedPrintable.Decode;
- var
- Buf : PChar;
- i : Integer;
- Finished : boolean;
- s : string;
- sLen : byte absolute s;
- begin
- Buf:=StrAlloc(BufSize);
- i:=-1;
- try
- repeat
- FillChar(Buf^,BufSize,0);
- repeat
- Inc(i);
- s:=Lines[i];
- ReplaceHex(s);
- Finished:=(sLen=0) or (s[sLen]<>'=');
- if not Finished then Dec(sLen)
- else s:=Concat(s,^M^J);
- s:=Concat(s,#00);
- if StrLen(Buf)+sLen>=BufSize then
- raise EMIMEError.Create('Paragraph is too large');
- StrCat(Buf,@s[1]);
- until Finished;
- Stream.Write(Buf^,StrLen(Buf));
- Application.ProcessMessages;
- until (i=Lines.Count-1) or Canceled;
- finally
- StrDispose(Buf);
- end;
- end;
-
- function GetContentType(const FileName : string) : string;
- var
- Ext : string[4];
- begin
- Ext:=UpperCase(ExtractFileExt(FileName));
- if Ext='.AIF' then result:='audio/aiff'
- else
- if (Ext='.AU') or (Ext='.SND') then result:='audio/basic'
- else
- if Ext='.GIF' then result:='image/gif'
- else
- if Ext='.JPG' then result:='image/jpeg'
- else
- if Ext='.AVI' then result:='video/avi'
- else
- if Ext='.RTF' then result:='text/rtf'
- else
- if Ext='.HTM' then result:='text/html'
- else
- if Ext='.TXT' then result:='text/plain'
- else
- result:='application/octet-stream';
- end;
-
- function MakeUniqueID : string;
- var
- i : Integer;
- begin
- Randomize;
- Result:='';
- for i:=1 to 8 do
- Result:=Concat(Result,IntToStr(Random(9)));
- end;
-
- end.
-